package com.code.refactoring.redis相关.分布式锁;

import redis.clients.jedis.Jedis;

import java.util.Collections;

/**
 * @Author wangxi
 * @Time 2019/10/20 23:23
 * 正确redis分布式加锁方式与解锁方式
 */
public class RedisTool {
    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";
    private static final Long RELEASE_SUCCESS = 1L;

    /**
     * 尝试获取分布式锁
     * @param requestId 请求标识
     * @param expireTime 超时时间(当系统崩溃或重启时，有作用。不仅仅是因为代码发生异常)
     * requestId一般可设置为 UUID.randomUUID().toString()+Thread.currentThread().getId()
     */
    public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {

        String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);

        if (LOCK_SUCCESS.equals(result)) {
            return true;
        }
        return false;

    }

    /**
     * 释放分布式锁
     * @param requestId 请求标识
     * @return 是否释放成功
     * 我们将Lua代码传到jedis.eval()方法里，并使参数KEYS[1]赋值为lockKey，ARGV[1]赋值为requestId。
     * eval()方法是将Lua代码交给Redis服务端执行
     */
    public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {

        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedis.eval(script, Collections.singletonList(lockKey),
                Collections.singletonList(requestId));

        if (RELEASE_SUCCESS.equals(result)) {
            return true;
        }
        return false;

    }
}
